package com.pxmeta.chat.service;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.pxmeta.chat.entity.ChatGroup;
import com.pxmeta.chat.entity.dto.UpdateGroupDTO;
import com.pxmeta.chat.entity.vo.*;
import com.pxmeta.chat.enums.MsgTypeEnum;
import com.pxmeta.chat.mapper.ChatGroupMapper;
import com.pxmeta.common.config.HuanxinConfig;
import com.pxmeta.common.core.redis.RedisCache;
import com.pxmeta.common.utils.HttpUtils;
import com.pxmeta.user.entity.User;
import com.pxmeta.user.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 文档地址： https://docs-im.easemob.com/ccim/rest/overview
 */
@Service
@RequiredArgsConstructor
public class HuanxinService {
    private final HuanxinConfig config;
    private final RedisCache redisCache;
    private final String TOKEN_KEY = "huanxin_accessToken";
    private final RestTemplate restTemplate;
    private final UserMapper userMapper;
    private final ChatGroupMapper chatGroupMapper;

    private final String TARGET_USERS = "users"; //给用户发消息
    private final String TARGET_CHAT_GROUPS = "chatgroups"; //给群发消息
    private final String TARGET_CHAT_ROOMS = "chatrooms"; //给聊天室发消息

    private String getToken() {
        String token = redisCache.getCacheObject(TOKEN_KEY);
        if (StringUtils.isBlank(token)) {
            JSONObject rst = config.getToken();
            token = rst.getString("access_token");
            redisCache.setCacheObject(TOKEN_KEY, token, 29, TimeUnit.DAYS);
        }
        return token;
    }


    public void register(String username, String password, String nickname) {
        String url = config.getBaseUrl() + "/users";
        HxUserVO user = new HxUserVO();
        user.setUsername(username);
        user.setPassword(password);
        user.setNickname(nickname);
        HttpEntity<HxUserVO> httpEntity = new HttpEntity<>(user, getHeader());
        try {
            JSONObject result = restTemplate.postForObject(url, httpEntity, JSONObject.class);
        } catch (RestClientException e) {
            e.printStackTrace();
        }
    }


    private HttpHeaders getHeader() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setBearerAuth(getToken());
        return headers;
    }

    private Map<String, String> getHeaderMap() {
        Map<String, String> map = Maps.newHashMap();
        map.put("Content-Type", MediaType.APPLICATION_JSON_VALUE);
        map.put("Authorization", "Bearer " + getToken());
        return map;
    }


    /**
     * 设置免打扰
     */
    public void setDisturb(String username, String start, String end) {
        String url = config.getBaseUrl() + "/users/" + username;
        HttpHeaders header = getHeader();
        DisturbVO vo = new DisturbVO();
        vo.setIsDisturbing(Boolean.TRUE);
        vo.setStart(start);
        vo.setEnd(end);
        HttpEntity<DisturbVO> httpEntity = new HttpEntity<>(vo,header);
        JSONObject rst = restTemplate.postForObject(url, httpEntity, JSONObject.class);
    }

    /**
     * 取消免打扰
     */
    public void cancelDisturb(String username) {
        String url = config.getBaseUrl() + "/users/" + username;
        HttpHeaders header = getHeader();
        DisturbVO vo = new DisturbVO();
        vo.setIsDisturbing(Boolean.FALSE);
        HttpEntity<DisturbVO> httpEntity = new HttpEntity<>(vo,header);
        JSONObject rst = restTemplate.postForObject(url, httpEntity, JSONObject.class);
    }

    public JSONArray batchUserStatus(List<String> usernames){
        String url = config.getBaseUrl() + "/users/batch/status";
        HttpHeaders header = getHeader();
        JSONObject obj = new JSONObject();
        obj.put("usernames",usernames);
        HttpEntity<JSONObject> entity = new HttpEntity<>(obj,header);
        JSONObject result = restTemplate.postForObject(url,entity,JSONObject.class);
        return result.getJSONArray("data");
    }


    /**
     * 给用户发送文字消息
     */
    public void sendTextToUser(String fromUsername, String targetUsername, String msg) {
        String url = config.getBaseUrl() + "/messages";
        HttpHeaders header = getHeader();
        //封装文本消息
        JSONObject msgObj = new JSONObject();
        msgObj.put("msg", msg);
        msgObj.put("type", MsgTypeEnum.TXT.getType());
        MsgVO vo = getCommonMsgToUser(fromUsername, targetUsername, msgObj, TARGET_USERS);
        HttpEntity<MsgVO> httpEntity = new HttpEntity<>(vo, header);
        restTemplate.postForObject(url, httpEntity, JSONObject.class);
    }




    /**
     * 给用户发送消息
     *
     * @param fromUsername
     * @param targetUsername
     * @param msg
     */
    public void sendMsgToUser(String fromUsername, String targetUsername, JSONObject msg, MsgTypeEnum type) {
        String url = config.getBaseUrl() + "/messages";
        HttpHeaders header = getHeader();
        msg.put("type", type.getType());
        MsgVO vo = getCommonMsgToUser(fromUsername, targetUsername, msg, TARGET_USERS);
        HttpEntity<MsgVO> httpEntity = new HttpEntity<>(vo, header);
        restTemplate.postForObject(url, httpEntity, JSONObject.class);
    }


    /**
     * 获取通用消息Vo
     *
     * @param from       发送人username
     * @param target     接收人
     * @param msgObj     消息体
     * @param targetType 类型 users：给用户发消息，chatgroups：给群发消息，chatrooms：给聊天室发消息。
     * @return
     */
    private MsgVO getCommonMsgToUser(String from, String target, JSONObject msgObj, String targetType) {
        MsgVO vo = new MsgVO();
        vo.setMsg(msgObj);
        vo.setTargetType(targetType);
        LinkedList<String> targets = Lists.newLinkedList();
        targets.add(target);
        vo.setTarget(targets);
        vo.setFrom(from);
        return vo;
    }


    private ChatMsgVO getCommonMsgToUser(String from, List<String> targets, JSONObject body, String type,JSONObject ext) {
        ChatMsgVO vo = new ChatMsgVO();
        vo.setBody(body);
        vo.setTo(targets);
        vo.setExt(ext);
        vo.setType(type);
        vo.setFrom(from);
        return vo;
    }


    /**
     * 添加好友
     *
     * @param ownerUsername
     * @param friendUsername
     */
    public void addFriend(String ownerUsername, String friendUsername) {
        String format = config.getBaseUrl() + "/users/%s/contacts/users/%s";
        String url = String.format(format, ownerUsername, friendUsername);

        HttpHeaders header = getHeader();
        HttpEntity<Object> httpEntity = new HttpEntity<>(header);
        restTemplate.postForObject(url, httpEntity, JSONObject.class);
    }


    /**
     * 删除好友
     *
     * @param ownerUsername
     * @param friendUsername
     */
    public void removeFriend(String ownerUsername, String friendUsername) {
        String format = config.getBaseUrl() + "/users/%s/contacts/users/%s";
        String url = String.format(format, ownerUsername, friendUsername);
        HttpHeaders header = getHeader();
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.APPLICATION_JSON);
        header.setAccept(mediaTypes);
        HttpEntity<Object> objectHttpEntity = new HttpEntity<>(header);
        restTemplate.exchange(url, HttpMethod.DELETE, objectHttpEntity, Void.class);
    }

    /**
     * 获取所有好友
     *
     * @param ownerUsername
     * @return
     */
    public FriendsVO getFriends(String ownerUsername, Integer page, Integer size, String keyword) {
        String format = config.getBaseUrl() + "/users/%s/contacts/users";
        String url = String.format(format, ownerUsername);
        Map<String, String> headerMap = getHeaderMap();

        JSONObject result = HttpUtils.doGet(url, headerMap);
        if (null == result) {
            return null;
        }

        Integer count = result.getInteger("count");
        JSONArray data = result.getJSONArray("data");

        List<String> usernameList = data.stream().map(Object::toString).collect(Collectors.toList());
        FriendsVO vo = new FriendsVO();
        if (CollectionUtil.isNotEmpty(usernameList)) {
            LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
            wrapper.in(User::getUsername, usernameList);
            if (StringUtils.isNotBlank(keyword)) {
                wrapper.like(User::getNickname, keyword);
            }
            List<User> users = userMapper.selectPage(new Page<>(page, size), wrapper).getRecords();
            vo.setFriends(users);
        }
        vo.setCount(count);
        return vo;
    }


    /**
     * 分页获取所有群聊
     *
     * @param limit
     * @param cursor
     * @return
     */
    public JSONArray getChatGroups(String limit, String cursor) {
        String url = config.getBaseUrl() + "/chatgroups?limit={limit}&curosor={curosor}";
        HashMap<String, Object> param = Maps.newHashMap();
        param.put("limit", limit);
        param.put("curosor", cursor);
        JSONObject body = restTemplate.getForObject(url, JSONObject.class, param);

        return body.getJSONArray("data");
    }

    public JSONArray getChatGroupAdmin(String groupId){
        String url = String.format(config.getBaseUrl() + "/chatgroups/%s/admin", groupId);
        JSONObject obj = HttpUtils.doGet(url, getHeaderMap());
        return obj.getJSONArray("data");
    }

    /**
     * 获取用户所有群聊（不分页）
     *
     * @param username
     * @return
     */
    public JSONArray getUserChatGroups(String username) {
        String url = config.getBaseUrl() + "/users/" + username + "/joined_chatgroups";
        Map<String, String> headerMap = getHeaderMap();
        JSONObject body = HttpUtils.doGet(url, headerMap);
        return body.getJSONArray("data");
    }


    /**
     * 获取群聊详情
     *
     * @param groupId
     * @return
     */
    public JSONArray getChatGroupsDetail(String groupId) {
        String url = config.getBaseUrl() + "/chatgroups/" + groupId;
        //        JSONObject body = restTemplate.getForObject(url, JSONObject.class, header);
        return HttpUtils.doGet(url, getHeaderMap()).getJSONArray("data");
    }


    /**
     * 创建群聊
     *
     * @param vo
     * @return
     */
    public JSONObject createChatGroups(JSONObject vo) {
        String url = config.getBaseUrl() + "/chatgroups";
        HttpHeaders header = getHeader();
        HttpEntity<JSONObject> entity = new HttpEntity<>(vo,header);
        ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url, entity, JSONObject.class);
        return responseEntity.getBody().getJSONObject("data");
    }


    public void updateChatGroups(UpdateGroupDTO dto){
        Long chatGroupId = dto.getChatGroupId();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("groupname",dto.getGroupName());
        jsonObject.put("description",dto.getDescription());
        jsonObject.put("maxusers",dto.getMaxUserCount());
        jsonObject.put("membersonly",dto.getMembersOnly());
        jsonObject.put("allowinvites",dto.getAllowInvites());
        String url = config.getBaseUrl() + "/chatgroups/" + chatGroupId;
        HttpHeaders header = getHeader();
        HttpEntity<JSONObject> entity = new HttpEntity<>(jsonObject, header);
        restTemplate.put(url,entity);

        ChatGroup chatGroup = chatGroupMapper.selectById(chatGroupId);
        chatGroup.setGroupName(dto.getGroupName());
        chatGroup.setDescription(dto.getDescription());
        chatGroup.setMaxusers(dto.getMaxUserCount());
        chatGroup.setMembersOnly(dto.getMembersOnly());
        chatGroup.setRemindOnlyAdmin(dto.getRemindOnlyAdmin());
        chatGroup.setAllowInvites(dto.getAllowInvites());

        chatGroupMapper.updateById(chatGroup);
    }

    /**
     * 删除群聊
     *
     * @param groupId
     */
    public void deleteChatGroup(String groupId) {
        String url = config.getBaseUrl() + "/chatgroups/" + groupId;
        HttpHeaders header = getHeader();
        HttpEntity<Object> objectHttpEntity = new HttpEntity<>(header);
        restTemplate.exchange(url, HttpMethod.DELETE,objectHttpEntity , Void.class, 1);
    }


    /**
     * 分页获取群组成员
     *
     * @param groupId
     * @param page
     * @param size
     * @return
     */
    public JSONArray getUserPage(String groupId, Integer page, Integer size) {
        String url = config.getBaseUrl() + "/chatgroups/" + groupId + "/users?page=%s&size=%s";

        JSONObject result = HttpUtils.doGet(String.format(url, page, size), getHeaderMap());
        return result.getJSONArray("data");
    }

    /**
     * 往群聊添加用户
     *
     * @param groupId
     * @param username
     * @return
     */
    public JSONObject addUserToChatGroups(String groupId, String username) {
        String url = config.getBaseUrl() + "/chatgroups/" + groupId + "/users/" + username;
        HttpHeaders header = getHeader();
        HttpEntity<Object> entity = new HttpEntity<>(header);
        JSONObject result = restTemplate.postForObject(url, entity, JSONObject.class);
        return result.getJSONObject("data");
    }


    /**
     * 将用户移出群聊
     *
     * @param groupId
     * @param username
     */
    public void removeUserByChatGroups(String groupId, String username) {
        String url = config.getBaseUrl() + "/chatgroups/" + groupId + "/users/" + username;
        HttpEntity<Object> objectHttpEntity = new HttpEntity<>(getHeader());
        restTemplate.exchange(url, HttpMethod.DELETE,objectHttpEntity , Void.class, 1);
    }

    /**
     * 添加群组管理员
     *
     * @param groupId
     * @param adminUsername
     */
    public void addAdminToChatGroups(String groupId, String adminUsername) {
        String url = config.getBaseUrl() + "/chatgroups/" + groupId + "/com.pxmeta.admin";
        JSONObject obj = new JSONObject();
        obj.put("newadmin", adminUsername);
        HttpHeaders header = getHeader();
        restTemplate.postForObject(url, obj, JSONObject.class, header);
    }

    /**
     * 取消群组管理员
     *
     * @param groupId
     * @param adminUsername
     */
    public void cancelChatGroupsAdmin(String groupId, String adminUsername) {
        String url = config.getBaseUrl() + "/chatgroups/" + groupId + "/com.pxmeta.admin" + adminUsername;
        restTemplate.delete(url, getHeader());
    }

    /**
     * 群组转让
     *
     * @param groupId
     * @param newOwner
     */
    public void transferChatGroups(String groupId, String newOwner) {
        String url = config.getBaseUrl() + "/chatgroups/" + groupId;
        HttpHeaders header = getHeader();
        JSONObject obj = new JSONObject();
        obj.put("newowner", newOwner);
        restTemplate.put(url, obj, header);
    }

    public void updateUser(ChatUserVO user, String username) {
        String url = config.getBaseUrl() + "/metadata/user/" + username;
        HttpHeaders header = getHeader();
        header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<String> entity = new HttpEntity<>(MessageFormat.format("nickname={0}&avatarurl={1}&gender={2}", user.getNickName(), user.getAvatarUrl(), user.getGender()), header);
        restTemplate.put(url, entity);
    }

    public void deleteUser(String username) {
        String url = config.getBaseUrl() + "/users/" + username;
        HttpHeaders header = getHeader();
        header.remove("Content-Type");
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.APPLICATION_JSON);
        header.setAccept(mediaTypes);
        HttpEntity<Object> objectHttpEntity = new HttpEntity<>(header);
        restTemplate.exchange(url, HttpMethod.DELETE, objectHttpEntity, Void.class, 1);
    }

    public void sendExtMsgToUser(String fromUsername, List<String> targetUsernames,String customEvent, JSONObject jsonObject) {
        String url = config.getBaseUrl() + "/messages/users";
        HttpHeaders header = getHeader();

        JSONObject body = new JSONObject();
        body.put("msg",jsonObject.getString("content"));
        body.put("customEvent",customEvent);
        body.put("customExts",jsonObject);
        ChatMsgVO vo = getCommonMsgToUser(fromUsername, targetUsernames, body, MsgTypeEnum.CUSTOM.getType(),null);

        HttpEntity<ChatMsgVO> httpEntity = new HttpEntity<>(vo, header);
        restTemplate.postForObject(url, httpEntity, JSONObject.class);
    }

    /**
     * 发送透传消息
     * @param targetUsernames
     * @param text
     */
    public void sendTransparentMsg(List<String> targetUsernames,String text) {
        String url = config.getBaseUrl() + "/messages/users";
        HttpHeaders header = getHeader();


        JSONObject body = new JSONObject();
        body.put("action","LiveGifts");

        JSONObject ext = new JSONObject();
        ext.put("text",text);
        ChatMsgVO vo = getCommonMsgToUser(null, targetUsernames, body, MsgTypeEnum.CMD.getType(), ext);
        HttpEntity<ChatMsgVO> httpEntity = new HttpEntity<>(vo, header);
        restTemplate.postForObject(url, httpEntity, JSONObject.class);
    }
}
